import {App, Button, Divider, Flex, Space, Spin, Tree} from "antd";
import {CloudUploadOutlined, ReloadOutlined, RetweetOutlined, SyncOutlined} from "@ant-design/icons";
import React, {useEffect, useRef, useState} from "react";
import RequestHandler from "@/http/RequestHandler.ts";
import LogFactory from "@/log/LogFactory.ts";
import type {MyTreeDataNode} from "@/common/tree/index";
import {treeIconConvert} from "@/common/tree/treeHandler.tsx";
import {compareArray} from "@/util/compare.ts";

interface IProps<T extends object>{
    /**
     * 更新数据时使用的数据id
     */
    id: number | string,
    /**
     * 是否严格受控，父子节点选中状态不再关联。
     */
    checkStrictly?: boolean,
    /**
     * 是否默认展开所有节点。
     */
    expandAll?: boolean,
    /**
     * 权限树渲染数据接口地址, 地址获取权限树数据,和默认需要选中的数据
     */
    treeRenderUrl: string,
    /**
     * 权限更新地址
     */
    authorityUpdateUrl?: string,
    /**
     * 权限树数据刷新地址,此地址只是用来刷新权限树,并不刷新选中项目
     */
    treeDataRefreshUrl?: string,
    /**
     * 树的节点title渲染函数
     * @param node 当前树节点数据
     * @param ExtendType 当前树的节点数据的扩展类型
     */
    titleRender?: (node: MyTreeDataNode<T>) => React.ReactNode;
}

type CheckedParamType = {checked: React.Key[] ; halfChecked: React.Key[]}

const log = LogFactory.getLogger("ProTree");

const ProTree =<T extends object> (props: IProps<T>) => {
    const [ isEdit, setIsEdit ] = useState<boolean>(false);
    // 是否运行刷新权限, 当提交后才允许
    const [ isRefresh, setIsRefresh ] = useState<boolean>(false);
    const [ loading, setLoading ] = useState<boolean>(true);
    const [ loadingBtn, setLoadingBtn ] = useState<boolean>(false);
    const [ data, setData ] = useState<MyTreeDataNode<T>[]>();
    const [checkedKeys, setCheckedKeys] = useState<React.Key[]>([]);
    const [expandedKeys, setExpandedKeys] = React.useState<React.Key[]>();

    const {message} = App.useApp();

    /**
     * 初始化权限,从服务器获取的权限数据备份
     */
    const initAuthorityRef = useRef<React.Key[]>([]);
    log.info("权限树组件加载-------------------------------->");
    useEffect(() => {
        RequestHandler.get<{treeData: MyTreeDataNode<T>[],authorityKeys: string[],expandKeys: string[]}>(props.treeRenderUrl)
            .then(res => {
                log.debug("树渲染数据",res);
                if (res.success){
                    const {treeData,authorityKeys,expandKeys} = res.data;
                    treeIconConvert(treeData);
                    setCheckedKeys(authorityKeys)
                    initAuthorityRef.current = authorityKeys;
                    setData(treeData);
                    setLoading(false);
                    if (expandKeys){
                        setExpandedKeys(expandKeys);
                    }
                }
            });
    }, []);

    const onCheck = (checked: React.Key[] | CheckedParamType) => {
        if (Array.isArray(checked)) {
            // log.debug("onCheck_", checked);
            onCheckHandler(checked);
        }else {
        // log.debug("onCheck", checked.checked);
            onCheckHandler(checked.checked);
        }
    }
    const onCheckHandler = (checked: React.Key[]) =>{
        const compRes = compareArray(initAuthorityRef.current,checked,props.id);
        // log.debug("用户选择权限_差异比较", checked,compRes);
        setCheckedKeys(checked);
        if (compRes === null){
            // 权限没有修改
            setIsEdit(false);
        }else {
            // 权限变化
            setIsEdit(true);
        }
    }
    const onExpand = (expandedKeys: React.Key[]) => {
        setExpandedKeys(expandedKeys);
    };
    const updateAuthority = async () => {
        setLoadingBtn(true);
        initAuthorityRef.current = checkedKeys;
        await message.success("修改权限成功!");
        setIsEdit(false);
        setIsRefresh(true);
        setLoadingBtn(false);
    }
    const refreshAuthority = async () => {
        setLoadingBtn(true);
        await message.success("刷新权限完成!");
        setIsRefresh(false);
        setLoadingBtn(false);
    }
    const refreshAuthorityTree = async () => {
        setLoadingBtn(true);
        await message.success("刷新权限树完成!");
        setLoadingBtn(false);
    }
    const recover = async () => {
        setCheckedKeys(initAuthorityRef.current);
        setIsEdit(false);
    }
    return (
        <Flex style={{paddingInline: "10px", overflow: "hidden"}} vertical>
            <Flex style={{marginBottom: "10px"}} justify={"space-between"}>
                <Space size={20}>
                    <Button loading={loadingBtn} icon={<RetweetOutlined />} type="primary" disabled={!isEdit} onClick={recover}>恢复权限</Button>
                    <Button loading={loadingBtn} icon={<CloudUploadOutlined />} type="primary" disabled={!isEdit} onClick={updateAuthority}>提交修改</Button>
                    <Button loading={loadingBtn} icon={<ReloadOutlined />} type={"primary"} disabled={!isRefresh} onClick={refreshAuthority}>刷新权限</Button>
                </Space>
                <Button loading={loadingBtn} type="primary" icon={<SyncOutlined />} onClick={refreshAuthorityTree}>刷新权限树</Button>
            </Flex>
           <Divider/>
            <Spin spinning={loading} size={"large"} tip={"获取渲染树数据中. . . "}>
                <Tree
                    treeData={data}
                    style={{ minHeight: "100px" }}
                    showIcon
                    checkable
                    showLine
                    blockNode
                    checkStrictly={props.checkStrictly}
                    defaultExpandAll={props.expandAll}
                    defaultExpandParent={props.expandAll}
                    autoExpandParent={props.expandAll}
                    checkedKeys={checkedKeys}
                    expandedKeys={expandedKeys}
                    onCheck={onCheck}
                    onExpand={onExpand}
                    titleRender={props.titleRender}
                />
            </Spin>
            <Divider/>
            <footer>
                <p>
                    <span style={{fontSize: "14px", fontWeight: "bold", color: "#9633d3"}}>权限操作说明：</span>
                    当修选择权限后，点击恢复权限按钮，即可恢复当前用户未修改前权限。
                </p>
                <p>
                    <span style={{fontSize: "14px", fontWeight: "bold", color: "#b11d3b"}}>权限修改说明：</span>
                    当修选择权限后，请先提交修，提交后刷新权限才能使权限即时生效。
                </p>
                <p>
                    <span style={{fontSize: "14px", fontWeight: "bold", color: "#108c25"}}>权限刷新说明：</span>
                    当修后台树数据更新后，可以点击刷新权限树按钮，对权限树进行刷新。
                </p>
            </footer>
        </Flex>
    );
};

export default ProTree;